package com.mijie.homi.ns.traffic;

import java.net.InetSocketAddress;
import java.nio.charset.Charset;

import javax.annotation.PostConstruct;

import net.sf.json.JSONObject;

import org.apache.log4j.Logger;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoHandler;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.mijie.homi.common.constant.HomiConstants;
import com.mijie.homi.common.constant.TypeCode;
import com.mijie.homi.common.protocol.HomiProtocol;
import com.mijie.homi.common.protocol.HomiProtocolCodecFactory;
import com.mijie.homi.ns.core.HomiServer;
import com.mijie.homi.ns.traffic.receptor.ChatMessageReceptor;
import com.mijie.homi.ns.traffic.receptor.Receptor;
import com.mijie.homi.ns.traffic.receptor.SolicitedMessageReceptor;
import com.mijie.homi.ns.traffic.receptor.SystemMessageReceptor;
import com.mijie.util.Helper;

@Service
public class MessageRouter {

	private NioSocketConnector connector;
	private IoSession session = null;
	private Receptor[] routerGroup;
	private Logger logger = Logger.getLogger(MessageRouter.class);
	
	@Autowired
	private ChatMessageReceptor chatMessageReceptor;
	@Autowired
	private SolicitedMessageReceptor solicitedMessageReceptor;
	@Autowired
	private SystemMessageReceptor systemMessageReceptor; 
	
	private MessageRouter(){
		connector = new NioSocketConnector();  
		connector.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new HomiProtocolCodecFactory( Charset.forName( "UTF-8" ))));
		connector.setHandler(new MessageDispatcher());
		connector.getSessionConfig().setKeepAlive(true);
		connectionToMessageRouter();
	}
	
	@PostConstruct
	private void setup(){
		routerGroup = new Receptor[3];
		routerGroup[0] = chatMessageReceptor;
		routerGroup[1] = solicitedMessageReceptor;
		routerGroup[2] = systemMessageReceptor;
	}
	
	private  void connectionToMessageRouter(){
		try{
			ConnectFuture future = connector.connect(new InetSocketAddress("localhost",HomiConstants.MESSAGE_ROUTER_PORT));
			future.awaitUninterruptibly();
			session = future.getSession();
		}catch(Exception e){
			logger.error(e.getMessage(), e);
			session = null;
		}
		logger.info("===========================connectionToMessageRouter==========================");
		
	}
	
	private Object reConnectionLock = new Object();
	public void sendMessage(HomiProtocol pack){
		if(session==null || !session.isConnected() || session.isClosing()){
			synchronized(reConnectionLock){
				if(session==null || !session.isConnected() || session.isClosing())
					connectionToMessageRouter();
			}
		}
		if(session!=null){
			session.write(pack);
		}
	}
	
	private class MessageDispatcher implements IoHandler {

		private Logger logger = Logger.getLogger(MessageDispatcher.class);
		
		public void exceptionCaught(IoSession session, Throwable cause)
				throws Exception {
			logger.error(cause.getMessage(), cause);
		}

		public void sessionClosed(IoSession session) throws Exception {
			logger.info("===============Disconnected with the message router===============");
		}

		public void sessionCreated(IoSession session) throws Exception {
			logger.info("===============Connected to the message router===============");
		}

		public void messageSent(IoSession session, Object message) throws Exception {
		}

		
		public void messageReceived(IoSession session, Object message){
			HomiProtocol msg = (HomiProtocol) message;
			if(msg.getContent()==null || msg.getContent().trim().isEmpty()){
				logger.info("messageReceived content is empty , mid:"+msg.getType()+",sender iosession id:"+session.getId());
				return;
			}
			
			if(msg.getType()!=TypeCode.MESSAGE_ROUTER_REPORT){
				logger.info("MessageDispatcher messageReceived,type:"+msg.getType()+",content:"+msg.getContent());
				HomiProtocol report = new HomiProtocol(TypeCode.MESSAGE_ROUTER_REPORT);
				report.setContent(msg.getId());
				session.write(report);
				JSONObject json = JSONObject.fromObject(msg.getContent());
				for(Receptor receptor : routerGroup){
					if(receptor.accept(msg.getType())){
						receptor.process(json.getInt("receiver"),(short)json.getInt("type"),json.getJSONObject("content"));
						break;
					}
				}
			}
		}

		public void sessionIdle(IoSession session, IdleStatus status)
				throws Exception {
		}

		public void sessionOpened(IoSession session) throws Exception {
			
		}
	}
}
